package edu.iscas.xcheck.utils.http;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class PostClient {
	
	private String host;
	private String port;
	private String path;
	private String address;
	
	private CloseableHttpClient httpClient;
	private HttpPost httpPost;
	
	
	private static final Logger LOG = LoggerFactory.getLogger(PostClient.class);
	
	public PostClient(String host, String port, String path){
		this.host = host;
		this.port = port;;
		this.path = (path.charAt(0) == '/') ? path : "/" + path;
		this.address = "http://" + this.host + ":" + this.port + this.path;
	    httpClient = HttpClients.createDefault();
	    httpPost = new HttpPost(address);  
	}

	public void setContent(String[] names,String[] values) throws IllegalArgumentException, UnsupportedEncodingException{
		if(names.length != values.length){
			throw new java.lang.IllegalArgumentException();
		}
	    List<NameValuePair> formparams = new ArrayList<NameValuePair>();
	    for(int i = 0; i < names.length ; i++){
	    	formparams.add(new BasicNameValuePair(names[i], values[i]));
	    }
	    UrlEncodedFormEntity uefEntity;
		uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8");
        httpPost.setEntity(uefEntity); 

	}
	public void setJsonContent(Object object) throws NullPointerException{
		if(object == null){
			throw new java.lang.NullPointerException(); 
		}
		ObjectMapper mapper = new ObjectMapper();
		StringEntity strEntity;
		String str = null;
		try {
			str = mapper.writeValueAsString(object);
		} catch (JsonProcessingException e) {
			e.printStackTrace();
		}
		LOG.debug(" Set HTTP Json Content: {}", str.toString());
		strEntity = new StringEntity(str, ContentType.APPLICATION_JSON);
		httpPost.setEntity(strEntity);
	}
	public static void main(String[] args){

	}
	public void setJsonContent(String[] names,String[] values) throws IllegalArgumentException{
		if(names.length != values.length){
			throw new java.lang.IllegalArgumentException();
		}
		StringEntity strEntity;
		StringBuffer sb = new StringBuffer();
		sb.append("{");
	    for(int i = 0; i < names.length ; i++){
	    	sb.append("\""+names[i]+"\"");
	    	sb.append(":");
	    	sb.append("\""+values[i]+"\"");
	    	if(i < names.length - 1) sb.append(",");
	    }
	    sb.append("}");
	    LOG.debug(" Set HTTP Json Content: {}", sb.toString());
	    
        strEntity = new StringEntity(sb.toString(),ContentType.APPLICATION_JSON);
		httpPost.setEntity(strEntity); 
	}
	
	/**
	 * Send request to the http://{@link #host}:{@link #port}/{@link #path}
	 * and call the responseHandler in the parameter when get the response
	 * @param responseHandler
	 * @return A value determined by the responseHandler
	 */
	public <T> T sendRequest(ResponseHandler<T> responseHandler){
		
		try {
			return httpClient.execute(httpPost, responseHandler);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		finally {
	        try {  
	        	httpClient.close();  
	        } catch (IOException e) {  
	        	e.printStackTrace();  
	        }  
		}
		return null;
	}
	/**
	 * Send request to the http://{@link #host}:{@link #port}/{@link #path}
	 * 
	 * @return The String of the body of response
	 */
	public String sendRequest() throws HttpResponseException, ClientProtocolException, IOException{
		
		ResponseHandler<String> rh = new ResponseHandler<String>(){
			@Override
			public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
				StatusLine statusLine = response.getStatusLine();
				HttpEntity entity = response.getEntity();
				if (statusLine.getStatusCode() >= 300) {
		            throw new HttpResponseException(
		                    statusLine.getStatusCode(),
		                    statusLine.getReasonPhrase());
		        }
				if (entity == null) {
		            throw new ClientProtocolException("Response contains no content");
		        }
				return EntityUtils.toString(entity, "UTF-8");
			}
			
		};
	
		try {
			return httpClient.execute(httpPost, rh);
		} catch (HttpResponseException e){
			throw e;
		} catch (ClientProtocolException e) {
			throw e;
		} catch (IOException e) {
			throw e;
		}
		finally {
	        try {  
	        	httpClient.close();  
	        } catch (IOException e) {  
	        	e.printStackTrace();  
	        }  
		}
	}
	public String getHost() {
		return host;
	}
	public void setHost(String host) {
		this.host = host;
	}
	public String getPort() {
		return port;
	}
	public void setPort(String port) {
		this.port = port;
	}
	public String getPath() {
		return path;
	}
	public void setPath(String path) {
		this.path = path;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public CloseableHttpClient getHttpClient() {
		return httpClient;
	}
	public void setHttpClient(CloseableHttpClient httpClient) {
		this.httpClient = httpClient;
	}
	public HttpPost getHttpPost() {
		return httpPost;
	}
	public void setHttpPost(HttpPost httpPost) {
		this.httpPost = httpPost;
	}

	@Override
	public String toString() {
		return "PostClient [host=" + host + ", port=" + port + ", path=" + path + ", address=" + address
				+ ", httpClient=" + httpClient + ", httpPost=" + httpPost + "]";
	}
 
}
